{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "#%matplotlib notebook"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Diccionarios\n",
    "Los *diccionarios* (`dict`) son la implementación en Python del concepto de *tabla hash*. Pueden verse como una generalización de las listas, en la que las posiciones, que eran enteros correlativos, han sido reemplazadas por valores genéricos.\n",
    "\n",
    "En otras palabras, un diccionario es una forma de asociar a ciertas *claves*, ciertos *valores*. Los valores pueden ser cualesquiera. **Las claves, valores inmutables**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Construcción\n",
    "Hay varias formas de crear diccionarios. Vemos las más habituales."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Construcción por enumeración\n",
    "Simplemente se especifican las asociaciones clave-valor entre llaves, separadas por comas."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Ejemplo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'ana': 18, 'antonio': 68, 'maria': 35, 'paco': 35}"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "edades = {'ana': 18, 'paco': 35, 'antonio': 68, 'maria': 35}\n",
    "edades"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "> Un primer hecho fundamental: en los diccionarios *no hay orden*."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cuando todas las claves son cadenas, existe una sintaxis alternativa:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'ana': 18, 'antonio': 68, 'maria': 35, 'paco': 35}"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "edades = dict(ana=18, paco=35, antonio=68, maria=35)\n",
    "edades"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    ""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Construcción a partir de una lista (o iterable) de pares\n",
    "Cada par se interpreta como `(clave, valor)`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "25"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "edades = dict( [('ana', 18), ('paco', 35), ('antonio', 68), ('maria', 35), ('ana', 25)] )\n",
    "edades['ana']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Acceso\n",
    "La operación más frecuente en diccionarios es la búsqueda del valor asociado a una clave. Sin ella no tienen sentido.\n",
    "\n",
    "La sintaxis es idéntica a la de listas: el operador `[]`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "68"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "edades['antonio']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "edades['elena']  # Busqueda de un dato que no existe\n",
    "\n",
    "Produce el error:\n",
    "```\n",
    "---------------------------------------------------------------------------\n",
    "NameError                                 Traceback (most recent call last)\n",
    "<ipython-input-1-aad97f8ef093> in <module>()\n",
    "----> 1 edades['elena']  # Busqueda de un dato que no existe\n",
    "\n",
    "NameError: name 'edades' is not defined\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Modificación\n",
    "Es la operación que asocia valores a claves. Puede involucrar una clave nueva, o bien reasignar una que ya existe."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    ""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "edades['elena'] = 0  # Llega una recien nacida"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'ana': 25, 'antonio': 68, 'elena': 0, 'maria': 35, 'paco': 35}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "edades"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'ana': 25, 'antonio': 68, 'elena': 0, 'maria': 35, 'paco': 36}"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Paco cumple hoy\n",
    "edades['paco'] += 1\n",
    "edades"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La operación sucede *in-place*: los diccionarios son mutables."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Borrado de una clave\n",
    "Podemos eliminar claves de diccionarios, con la misma primitiva que borra slices en listas: `del`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "del edades['paco']\n",
    "edades"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Algunas operaciones con diccionarios\n",
    "El tipo `dict` proporciona un gran abanico de métodos. Aquí vemos los imprescindibles."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Chequeo de pertenencia\n",
    "Devuelve un valor de verdad: el correspondiente a comprobar si un valor dado está entre las claves del diccionario."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "'elena' in edades"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "'javier' in edades"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "18 in edades  # El resultado es False, porque 18 es un valor, no una clave."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> Esta operación es **muy** eficiente."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Lista de claves\n",
    "El método `keys` devuelve un iterable con las claves del diccionario. Las coloca en un orden cualquiera.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['ana', 'paco', 'antonio', 'maria', 'elena']"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(edades.keys())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Lista de valores\n",
    "Igualmente, el método `values` devuelve uniterable con los valores asociados a las claves del diccionario. De nuevo, en un orden cualquiera."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[25, 36, 68, 35, 0]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(edades.values())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Lista de items\n",
    "El método `items` proporciona un iterable con los pares `(clave, valor)` del diccionario."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[('ana', 25), ('paco', 36), ('antonio', 68), ('maria', 35), ('elena', 0)]"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(edades.items())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejemplo 1: Frecuencia de letras en El Quijote\n",
    "Tenemos un fichero `'quijote.txt'`, con El Quijote en texto plano. Queremos hacer un histograma de frecuencias de cada letra, es decir, saber qué porcentaje de veces aparece la `'a'`, la `'b'`, etc.\n",
    "\n",
    "La herramienta perfecta para llevar el recuento es un diccionario, que asocia a cada letra el número de apariciones."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#urlWords = r'https://www.gutenberg.org/files/2000/2000-8.txt'\n",
    "\n",
    "# Lo hacemos como ejercicio.\n",
    "# Para leer un fichero:\n",
    "#with open(urlWords) as f:\n",
    "#    for line in f:\n",
    "\n",
    "# ------------------------------------------------------------\n",
    "# Cuantas e hay en el fichero?\n",
    "\n",
    "urlWords = r'files/quijote.txt'\n",
    "\n",
    "# EJERCICIO"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "f=open(\"C:/Users/mfc06/Desktop/quijote.txt\",\"r\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "0\n",
      "0\n"
     ]
    }
   ],
   "source": [
    "lines = 0\n",
    "words = 0\n",
    "characters = 0\n",
    "for line in f:\n",
    "    wordslist = line.split()\n",
    "    lines = lines + 1\n",
    "    words = words + len(wordslist)\n",
    "    characters = characters + len(line)\n",
    "print(lines)\n",
    "print(words)\n",
    "print(characters)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "d=dict()\n",
    "for a in f:\n",
    "    if d.has_key(a):\n",
    "        d[a]=d[a]+1\n",
    "    else:\n",
    "        d[a]=1\n",
    " \n",
    "print (a\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a href=\"solutions/diccionarios/ejercicio1_quijote.ipynb\"><img src=\"images/solucion.jpg\" width=\"200\" height=\"200\"/></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejemplo: sorteo distribución discreta\n",
    "El módulo `random` define una función `choice`, que devuelve un valor al azar en una lista, elegido uniformemente."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import random\n",
    "random.choice(['A', 'B', 'C', 'D'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lo que queremos es una generalización: la elección según una distribución discreta, dada por un diccionario que asocia a cada valor posible su probalilidad. Nos apoyamos en `random.uniform`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Ejercicio: Definir una funcion llamada choiceWeighted, que recibe un diccionario (str, float) de probabilidades \n",
    "# y dice la clave que sale en un sorteo\n",
    "def choiceWeighted(dist):\n",
    "    pass # Esto es una palabra reservada en python :-)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "choiceWeighted(dict(A=0.60, B=0.3, C=0.1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Comprobar que funciona bien"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejemplo: Tiempo esperado de quiebra\n",
    "Tenemos un grafo de ratings, y las probabilidades anuales de transición anual entre estados.\n",
    "<img src='images/figTransicRatings.svg'>\n",
    "El estado `Q` representa la quiebra, y es imposible salir de él. Queremos estimar, por simulación, el tiempo medio de quiebra desde cada uno de los estados."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "## Ejercicio: Codificar el arbol en forma de diccionario\n",
    "\n",
    "transicEsq1 = None  # ...."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def tiempoQuiebra(transic, estadoInic, estadoQuieb):\n",
    "    # Definimos el tiempo hasta la quiebra\n",
    "    pass\n",
    "\n",
    "\n",
    "def estimProbsQuiebra(transic, estadoQuieb, nSims=1000):\n",
    "    # Utilizamos la funcion tiempoQuiebra para estimar la probabilidad\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "estimProbsQuiebra(transicEsq1, 'Q', nSims=10000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> Este problema es un problema conocido en *cadenas de Markov*: el tiempo esperado de llegada a un\n",
    "*estado absorbente*. Tiene una solución algebraica exacta, que veremos en el módulo de programación científica."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a href=\"solutions/diccionarios/ejercicio2_timetodefault.ipynb\"><img src=\"images/solucion.jpg\" width=\"200\" height=\"200\"/></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejemplo: Caso del sesgo sexista en Berkeley U.\n",
    "Disponemos de los datos de solicitud de matriculación en las licenciaturas impartidas en la [Universidad de Berkeley](http://www.berkeley.edu/). Identifican alumno, género, licenciatura solicitada y el resultado dado a la solicitud (aceptación o rechazo).\n",
    "\n",
    "En concreto, en un fichero plano con el formato\n",
    "\n",
    "```\n",
    "65066360L,M,History,Accepted\n",
    "38927813D,W,Physics,Refused\n",
    "47610244N,M,English Liturature,Accepted\n",
    "90737521K,M,English Liturature,Accepted\n",
    "16186831P,W,Mathematics,Refused\n",
    "06742906I,W,Physics,Refused\n",
    "...\n",
    "```\n",
    "\n",
    "Debemos estudiar una acusación, que afirma que Berkeley discrimina a las mujeres."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "¿Cómo comprobarlo? Calculemos el porcentaje de mujeres que se han visto rechazadas, frente al de hombres."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "## EJERCICIO\n",
    "# Para poder leer un fichero haremos algo como lo siguiente:\n",
    "# with open(filename) as f:\n",
    "#    -- lo que sea que hagamos con el fichero\n",
    "# -- continuacion del codigo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Visto lo anterior, la dirección del centro se preocupa, y se dispone a reconvenir a los responsables de selección. Pero para ser justos, decide hacer el análisis individualizado por licenciatura, para dirigirse sólo a los departamentos culpables del sesgo. Repitamos el análisis anterior, pero para cada licenciatura."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Idem\n",
    "\n",
    "filename = 'files/berkeleyData.csv'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a href=\"solutions/diccionarios/ejercicio3_berkeley.ipynb\"><img src=\"images/solucion.jpg\" width=\"200\" height=\"200\"/></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hacemos un gráfico de barras."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from matplotlib.ticker import FuncFormatter\n",
    "\n",
    "generos = {\n",
    "    'W': 'Mujeres',\n",
    "    'M': 'Hombres',\n",
    "}\n",
    "\n",
    "def to_percent(y, position):\n",
    "    \"\"\"Produce numeros en porcentaje, sin trailing 0s\"\"\"\n",
    "    return str(100 * y).rstrip('0').rstrip('.') + '%'\n",
    "\n",
    "\n",
    "plt.figure(1, figsize = (10,5))  # Dimensiones zona plot\n",
    "axes = plt.gca()\n",
    "\n",
    "ancho = 0.3\n",
    "nDatos = len(subjects)\n",
    "x_pos = np.linspace(ancho, ancho*nDatos, nDatos)  # Alturas a las que va cada barra\n",
    "\n",
    "# Rangos abarcados en los ejes\n",
    "axes.set_xlim([(1-0.5)*ancho, ancho*(nDatos+0.5)])\n",
    "axes.set_ylim([0, 0.95])\n",
    "\n",
    "# Porcentajes en el eje X\n",
    "axes.yaxis.set_major_formatter(FuncFormatter(to_percent))\n",
    "\n",
    "# Plots por sexo\n",
    "for gen, offset, col in ( ('W', -0.16*ancho, 'r'), ('M', +0.16*ancho, 'b') ):\n",
    "    xs = x_pos + offset\n",
    "    ratio = []\n",
    "    for subj in subjects:\n",
    "        acc = frecs[(gen, subj, 'Accepted')]\n",
    "        ref = frecs[(gen, subj, 'Refused')]\n",
    "        ratio.append( acc / (acc + ref) )\n",
    "    plt.bar(xs, height=ratio, width=0.3*ancho, color=col, label=generos[gen], xerr=None, align='center', alpha=0.4)\n",
    "\n",
    "# Settings generales de la grafica\n",
    "plt.xticks(x_pos, subjects)  # Cambio en los xticks: ponemos las licenciaturas\n",
    "plt.xlabel('Licenciatura')\n",
    "plt.ylabel('Ratio Aceptación')\n",
    "plt.title('Solicitudes matriculación Berkeley U.')\n",
    "plt.legend(loc=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Resulta que en todas y cada una de las licenciaturas el porcentaje de hombres rechazados es mayor que el de mujeres. No hay discriminación contra ellas."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Los datos utilizados **no son reales** (de hecho, ¡están generados por un script Python!). Pero la paradoja sí, se conoce como [Paradoja de Simpson](https://en.wikipedia.org/wiki/Simpson%27s_paradox), y en efecto se dio en Berkeley con las matriculaciones de 1973."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Diccionarios Intensionales\n",
    "De forma totalmente análoga a como funciona para listas, existe una sintaxis especial para definir *diccionarios intensionales*.\n",
    "```python\n",
    "{exprClave:exprValor for e in <iterable> if cond(e)}\n",
    "```\n",
    "Por ejemplo, supongamos que tenemos una lista de palabras"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "palabras = [\"Esta\", \"semana\", \"tristemente\", \"no\", \"es\", \"demasiado\", \"especial\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Queremos construir la lista que asocia a cada palabra, escrita en minúsculas, su longitud. Pero solo para aquellas que contienen la letra `'a'`. Hacemos:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "longitudes = {p.lower():len(p) for p in palabras if 'a' in p}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "print(longitudes)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Diccionarios Especiales\n",
    "Aparte de los diccionarios que ya hemos comentado, existen un par de extensiones interesantes a los mismos, si bien la filosofía que subyace por detrás es la misma:\n",
    "\n",
    "* Datos organizados en claves y valores, donde la clave es única y el valor puede ser cualquier cosa.\n",
    "\n",
    "Recordar que un diccionario puede ser visto como una lista donde para acceder al elemento del array en lugar de acceder por índice accedemos por clave."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Diccionarios \"ordenados\"\n",
    "Este tipo de diccionarios nos permite, a diferencia de los diccionarios habituales, establecer un orden en las claves.\n",
    "El orden que se establece en las claves es el orden de asignación.\n",
    "\n",
    "Para poder utilizarlo, hay que importar el objeto **OrderedDict** de la librería **collections**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from collections import OrderedDict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d = OrderedDict()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d['B'] = 2\n",
    "d['A'] = 1\n",
    "d['E'] = 5\n",
    "d['D'] = 4\n",
    "d['C'] = 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "print(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Como podemos comprobar, el funcionamiento es igual que con los diccionarios habituales"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d['A']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d1 = {} # Sin ordenar..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d1['B'] = 2\n",
    "d1['A'] = 1\n",
    "d1['E'] = 5\n",
    "d1['D'] = 4\n",
    "d1['C'] = 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "print(d1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "for k, v in d1.items():\n",
    "    print(\"%s - %d\" % (k, v))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Si comprobamos un diccionario \"normal\" con otro desordenando en qué momento se introducen las claves, tendremos como resultado realmente el mismo objeto"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d2={}\n",
    "\n",
    "d2['A'] = 1\n",
    "d2['B'] = 2\n",
    "d2['C'] = 3\n",
    "d2['D'] = 4\n",
    "d2['E'] = 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d1==d2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "No obstante, si hacemos esto mismo con un diccionario ordenado la igualdad no ocurre salvo que hayamos introducido las claves en el mismo orden."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d3=OrderedDict()\n",
    "d3['B'] = 2\n",
    "d3['A'] = 1\n",
    "d3['E'] = 5\n",
    "d3['D'] = 4\n",
    "d3['C'] = 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d==d3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d4=OrderedDict()\n",
    "d4['B'] = 2\n",
    "d4['A'] = 1\n",
    "d4['E'] = 5\n",
    "d4['C'] = 3\n",
    "d4['D'] = 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d4==d3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Diccionarios con valores por defecto\n",
    "Este tipo de diccionarios nos permite, a diferencia de los diccionarios habituales, establecer un valor por defecto en las claves nuevas/no existentes. \n",
    "\n",
    "Como valor por defecto podemos establecer distintos tipos (por ejemplo, entero, lista, ...)\n",
    "\n",
    "Para poder utilizarlo, hay que importar el objeto **defaultdict** de la librería **collections**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from collections import defaultdict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d = defaultdict(int)\n",
    "d['prueba'] += 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lo bueno de este tipo de diccionarios es que nunca nos van a dar un error de clave :-)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d['unaclave que no existe']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Podemos definir un objeto un pelín más complicado... por ejemplo, una lista"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "d2 = defaultdict(list)\n",
    "d2['Prueba'].append(17)\n",
    "\n",
    "print(d2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<table border=\"0\">\n",
    "<tr>\n",
    "<td>\n",
    "<a href=\"mfc_sesion2_5_conjuntos.ipynb\">Anterior</a>\n",
    "</td>\n",
    "</tr>\n",
    "</table>"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3.0
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}